From 9d2aa7d13ac421935de1e87301c48af50b0ceb59 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=C3=98yvind=20Kol=C3=A5s?= Date: Sat, 17 Mar 2012 17:02:44 +0000 Subject: [PATCH] palette: add capability to use palette formats with separate alpha Also refactored to make babl-palette.c only use public API. --- babl/babl-fish-path.c | 6 +- babl/babl-format.c | 14 +++ babl/babl-ids.h | 1 - babl/babl-palette.c | 226 ++++++++++++++++++++++++++++++------------ babl/babl.h | 18 +++- tests/palette.c | 39 +++++++- 6 files changed, 230 insertions(+), 74 deletions(-) diff --git a/babl/babl-fish-path.c b/babl/babl-fish-path.c index c7caa35..a2d1a68 100644 --- a/babl/babl-fish-path.c +++ b/babl/babl-fish-path.c @@ -287,7 +287,8 @@ babl_fish_path (const Babl *source, pc.fish_path = babl; pc.to_format = (Babl *) destination; - babl_mutex_lock (babl_format_mutex); + if (babl_in_fish_path <= 0) + babl_mutex_lock (babl_format_mutex); /* we hold a global lock whilerunning get_conversion_path since * it depends on keeping the various format.visited members in * a consistent state, this code path is not performance critical @@ -298,7 +299,8 @@ babl_fish_path (const Babl *source, get_conversion_path (&pc, (Babl *) source, 0, max_path_length ()); babl_in_fish_path--; - babl_mutex_unlock (babl_format_mutex); + if (babl_in_fish_path <= 0) + babl_mutex_unlock (babl_format_mutex); babl_free (pc.current_path); } diff --git a/babl/babl-format.c b/babl/babl-format.c index d95384e..21d33e9 100644 --- a/babl/babl-format.c +++ b/babl/babl-format.c @@ -619,4 +619,18 @@ babl_format_loss (Babl *babl) return loss; } + +void * +babl_get_user_data (Babl *babl) +{ + return babl->format.model->data; +} + +void +babl_set_user_data (Babl *babl, void *data) +{ + babl->format.model_data = data; + babl->format.model->data = babl->format.model_data; +} + BABL_CLASS_IMPLEMENT (format) diff --git a/babl/babl-ids.h b/babl/babl-ids.h index f26add8..f0f6c61 100644 --- a/babl/babl-ids.h +++ b/babl/babl-ids.h @@ -85,7 +85,6 @@ enum { BABL_CB, BABL_CR, BABL_PADDING, - BABL_PAL, BABL_COMPONENT_LAST_INTERNAL, BABL_FORMAT_BASE = 100000, diff --git a/babl/babl-palette.c b/babl/babl-palette.c index c8f10d0..9fc525a 100644 --- a/babl/babl-palette.c +++ b/babl/babl-palette.c @@ -16,17 +16,10 @@ * . */ -#include "config.h" #include - -#include "babl-internal.h" -#include "babl-classes.h" +#include +#include #include "babl.h" -#include "babl-ids.h" -#include "util.h" -#include "rgb-constants.h" -#include "math.h" -#include "babl-base.h" typedef struct BablPalette { @@ -40,10 +33,10 @@ static BablPalette *make_pal (Babl *format, void *data, int count) { BablPalette *pal = NULL; int bpp = babl_format_get_bytes_per_pixel (format); - pal = babl_malloc (sizeof (BablPalette)); + pal = malloc (sizeof (BablPalette)); pal->count = count; pal->format = format; - pal->data = babl_malloc (bpp * count); + pal->data = malloc (bpp * count); memcpy (pal->data, data, bpp * count); return pal; } @@ -67,7 +60,6 @@ static unsigned char defpal_data[4*16] = 0 ,255,255,255, 255,255,255,255, }; - static BablPalette *default_palette (void) { static BablPalette pal; @@ -76,7 +68,10 @@ static BablPalette *default_palette (void) return &pal; inited = 1; pal.count = 16; - pal.format = babl_format ("RGBA u8"); + pal.format = babl_format ("RGBA u8"); /* dynamically generated, so + the default palette can + not be fully static. + */ pal.data = defpal_data; return &pal; } @@ -92,13 +87,9 @@ rgba_to_pal (char *src, Babl *fish; int bpp; - if (babl_in_fish_path) - babl_mutex_unlock (babl_format_mutex); fish = babl_fish ( pal->format, - babl_format_from_id (BABL_RGBA_DOUBLE)); - if (babl_in_fish_path) - babl_mutex_lock (babl_format_mutex); + babl_format ("RGBA double")); bpp = babl_format_get_bytes_per_pixel (pal->format); while (n--) @@ -139,6 +130,63 @@ rgba_to_pal (char *src, return n; } +static long +rgba_to_pala (char *src, + char *dst, + long n, + void *foo, + void *dst_model_data) +{ + BablPalette *pal = dst_model_data; + Babl *fish; + int bpp; + + fish = babl_fish ( + pal->format, + babl_format ("RGBA double")); + + bpp = babl_format_get_bytes_per_pixel (pal->format); + + while (n--) + { + int idx; + + int best_idx = 0; + double best_diff = 100000; + double *srcf; + double alpha; + + srcf = ((double *) src); + alpha = srcf[3]; + + for (idx = 0; idxcount; idx++) + { + double diff; + double palpx[4]; + + /* oh horror, at least cache the format */ + babl_process (fish, ((char*)pal->data) + idx * bpp, + palpx, 1); + + diff = (palpx[0] - srcf[0]) * (palpx[0] - srcf[0]) + + (palpx[1] - srcf[1]) * (palpx[1] - srcf[1]) + + (palpx[2] - srcf[2]) * (palpx[2] - srcf[2]); + if (diff < best_diff) + { + best_diff = diff; + best_idx = idx; + } + } + + ((double *) dst)[0] = best_idx / 256.0; + ((double *) dst)[1] = alpha; + + src += sizeof (double) * 4; + dst += sizeof (double) * 2; + } + return n; +} + static long pal_to_rgba (char *src, char *dst, @@ -149,14 +197,13 @@ pal_to_rgba (char *src, BablPalette *pal = src_model_data; Babl *fish = babl_fish ( pal->format, - babl_format_from_id (BABL_RGBA_DOUBLE)); + babl_format ("RGBA double")); int bpp = babl_format_get_bytes_per_pixel (pal->format); while (n--) { - int idx; + int idx = (((double *) src)[0]) * 256.0; - idx = (((double *) src)[0]) * 256.0; if (idx < 0) idx = 0; if (idx >= pal->count) idx = pal->count-1; @@ -171,7 +218,42 @@ pal_to_rgba (char *src, return n; } -Babl *babl_new_palette (const char *name) + +static long +pala_to_rgba (char *src, + char *dst, + long n, + void *src_model_data, + void *foo) +{ + BablPalette *pal = src_model_data; + Babl *fish = babl_fish ( + pal->format, + babl_format ("RGBA double")); + int bpp = babl_format_get_bytes_per_pixel (pal->format); + + while (n--) + { + int idx = (((double *) src)[0]) * 256.0; + double alpha = (((double *) src)[1]); + + + if (idx < 0) idx = 0; + if (idx >= pal->count) idx = pal->count-1; + + babl_process (fish, + ((char*)pal->data) + idx * bpp, + dst, 1); + + ((double *)dst)[3] *= alpha; + + src += sizeof (double) * 2; + dst += sizeof (double) * 4; + } + return n; +} + +Babl *babl_new_palette (const char *name, int with_alpha) { Babl *model; Babl *format; @@ -180,46 +262,69 @@ Babl *babl_new_palette (const char *name) if (!name) { static int cnt = 0; - sprintf (cname, "pal-%i", cnt++); + sprintf (cname, "_babl-int-%i", cnt++); name = cname; } + /* re-registering is a no-op */ babl_component_new ( "I", - "id", BABL_PAL, "luma", "chroma", "alpha", NULL); - model = babl_model_new ( - "name", name, - babl_component_from_id (BABL_PAL), - NULL); - model->model.data = (void*) 0x012; - - babl_conversion_new ( - model, - babl_model_from_id (BABL_RGBA), - "linear", pal_to_rgba, - NULL - ); - - babl_conversion_new ( - babl_model_from_id (BABL_RGBA), - model, - "linear", rgba_to_pal, - NULL - ); - - format = babl_format_new ("name", name, model, - babl_type ("u8"), - babl_component ("I"), NULL); - - format->format.model_data = default_palette (); - format->format.model->data = format->format.model_data; + if (with_alpha) + { + model = babl_model_new ("name", name, + babl_component ("I"), + babl_component ("A"), + NULL); + format = babl_format_new ("name", name, model, + babl_type ("u8"), + babl_component ("I"), + babl_component ("A"), + NULL); + + babl_conversion_new ( + model, + babl_model ("RGBA"), + "linear", pala_to_rgba, + NULL + ); + + babl_conversion_new ( + babl_model ("RGBA"), + model, + "linear", rgba_to_pala, + NULL + ); + } + else + { + model = babl_model_new ("name", name, + babl_component ("I"), + NULL); + babl_conversion_new ( + model, + babl_model ("RGBA"), + "linear", pal_to_rgba, + NULL + ); + + babl_conversion_new ( + babl_model ("RGBA"), + model, + "linear", rgba_to_pal, + NULL + ); + format = babl_format_new ("name", name, model, + babl_type ("u8"), + babl_component ("I"), NULL); + } + babl_set_user_data (format, default_palette ()); babl_sanity (); return format; } @@ -230,25 +335,18 @@ babl_palette_set_palette (Babl *babl, void *data, int count) { - if (babl->format.model->data != default_palette ()) - { - BablPalette *pal = babl->format.model->data; - babl_free (pal->data); - babl_free (pal); - } - babl->format.model_data = make_pal (format, data, count); - babl->format.model->data = babl->format.model_data; + babl_palette_reset (babl); + babl_set_user_data (babl, make_pal (format, data, count)); } void babl_palette_reset (Babl *babl) { - if (babl->format.model->data != default_palette ()) + if (babl_get_user_data (babl) != default_palette ()) { - BablPalette *pal = babl->format.model->data; - babl_free (pal->data); - babl_free (pal); + BablPalette *pal = babl_get_user_data (babl); + free (pal->data); + free (pal); } - babl->format.model_data = default_palette (); - babl->format.model->data = babl->format.model_data; + babl_set_user_data (babl, default_palette ()); } diff --git a/babl/babl.h b/babl/babl.h index e4b0082..57b2895 100644 --- a/babl/babl.h +++ b/babl/babl.h @@ -202,9 +202,10 @@ Babl * babl_conversion_new (void *first_arg, /** * create a new palette based format, name is optional pass in NULL to get - * an anonymous format. + * an anonymous format. If you pass in with_alpha the format also gets + * an 8bit alpha channel. */ -Babl *babl_new_palette (const char *name); +Babl *babl_new_palette (const char *name, int with_alpha); /** * Assign a palette to a palette format, the data is a single span of pixels @@ -221,6 +222,19 @@ void babl_palette_set_palette (Babl *babl, void babl_palette_reset (Babl *babl); +/** + * associate a data pointer with a format/model, this data can be accessed and + * used from the conversion functions, encoding color profiles, palettes or + * similar with the data. + */ +void babl_set_user_data (Babl *babl, void *data); + +/** + * get data set with babl_set_user_data + */ +void * babl_get_user_data (Babl *babl); + + /* * Backwards compatibility stuff diff --git a/tests/palette.c b/tests/palette.c index 02f79ac..afd52f9 100644 --- a/tests/palette.c +++ b/tests/palette.c @@ -58,8 +58,8 @@ main (int argc, { unsigned char in[][1] = {{ 0},{ 1},{ 2},{15}}; unsigned char out[][4] = {{0,0,0,255},{127,0,0,255},{0,127,0,255},{255,255,255,255}}; - Babl *palA = babl_new_palette (NULL); - Babl *palB = babl_new_palette (NULL); + Babl *palA = babl_new_palette (NULL, 0); + Babl *palB = babl_new_palette (NULL, 0); CHECK_CONV("pal to rgba", unsigned char, palA, babl_format("RGBA u8"), @@ -79,7 +79,16 @@ main (int argc, unsigned char out[][1] = {{ 0},{ 1},{ 2}}; CHECK_CONV("rgba to pal", unsigned char, - babl_format("RGBA u8"), babl_new_palette ("palC"), + babl_format("RGBA u8"), babl_new_palette ("palC", 0), + in, out); + } + + { + unsigned char in[][4] = {{0,0,0,255},{140,0,0,255},{0,127,0,127}}; + unsigned char out[][2] = {{ 0,255},{ 1,255},{ 2,127}}; + + CHECK_CONV("rgba to pal+alpha", unsigned char, + babl_format("RGBA u8"), babl_new_palette ("palD", 1), in, out); } @@ -91,10 +100,10 @@ main (int argc, 1.0, 0.2 }; - unsigned char in[][1] = {{ 0},{ 1},{ 2}}; + unsigned char in[][1] = {{ 0},{ 1},{ 2}}; unsigned char out[][4] = {{128,128,128,255},{59,59,59,107},{255,255,255,51}}; - Babl *pal = babl_new_palette (NULL); + Babl *pal = babl_new_palette (NULL, 0); babl_palette_set_palette (pal, babl_format ("YA float"), palette, 3); @@ -103,6 +112,26 @@ main (int argc, in, out); } + /* check with a custom floating point palette, _and_ alpha component */ + { + float palette[] = { + 0.5, 1.0, + 0.23, 0.42, + 1.0, 0.2 + }; + + unsigned char in[][2] = {{ 0,255},{0,127},{ 1,255},{ 2,255}}; + unsigned char out[][4] = {{128,128,128,255},{128,128,128,127},{59,59,59,107},{255,255,255,51}}; + + Babl *pal = babl_new_palette (NULL, 1); + + babl_palette_set_palette (pal, babl_format ("YA float"), palette, 3); + + CHECK_CONV("rgba to YA float pal+alpha", unsigned char, + pal, babl_format("RGBA u8"), + in, out); + } + babl_exit (); return !OK; } -- 2.30.2